/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: MrUtil.java,v $
 *
 */
package com.cidero.util;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Map;
import java.util.logging.Logger;
import java.util.logging.Level;

import javax.swing.ImageIcon;

/**
 *  
 */
public class MrUtil
{
  private static Logger logger = Logger.getLogger("com.cidero.util.MrUtil");
  private static Map envMap = null;

  static 
  {
    Properties sysProperties = System.getProperties();
    
    String home = sysProperties.getProperty("java.home");
    String version = sysProperties.getProperty("java.version");
    if( (home == null) || (version == null ) )
      System.out.println("Error accessing System properties!");
    else
      System.out.println("Java Home: " + home + " Version: " + version );

    // if( version.indexOf("1.5") >= 0 )
    // envMap = System.getenv();

  }
  
  /**
   * Sleep for the specified number of milliseconds. Wrapper of system
   * method that discards the exception
   *
   * @param millis
   */
  public static void sleep( long millis )
  {
    try
    {
      Thread.sleep( millis );
    }
    catch( Exception e )
    {
    }
  }
  
  public static String getUserHomeUnix()
  {
    String userHome = System.getProperty("user.home");
    userHome = userHome.replaceAll("\\\\","/");
    return userHome;
  }
  

  /**
   * @param fileName -
   *            The filename to search classpath for
   * @return The description file as File type.
   */
  public static File getResourceAsFile(String fileName)
  {

    String resolvedFileName = getResourcePath(fileName);
    return new File(resolvedFileName);
  }

  /**
   * @param fileName -
   *            The filename to search classpath for.
   * @return The canonical file name
   */
  public static String getResourcePath(String fileName)
  {
    URL url = ClassLoader.getSystemResource(fileName);
    if (url != null) {
      // Return the file name as found on classpath.
      //System.out.println("MrUtil.getResourcelPath, in = " + fileName + " Out = " + url.getFile());
      //return url.getFile();
      try
      {
        return URLDecoder.decode( url.getFile(), "UTF-8");
      }
      catch( UnsupportedEncodingException e )
      {
        logger.warning("Unsupported encoding");  // should never happen
        return null;
      }
    } else {
      // Just erturn input if can't find on classpath
      // Perhaps it is relative from current dir.
      return fileName;
    }
  }

  public static ImageIcon createImageIcon(String iconFileName)
  {
    return createImageIcon(iconFileName, null);
  }

  public static ImageIcon createImageIcon(String iconFileName,
                                          String description)
  {
    // All icons stored under project/build/icons.  Eclipse has
    // 'build' in class path by default, so add the icons subdir
    // here so we don't need to add properties subdir to class path
    String iconPath = "icons/" + iconFileName;


    String resolvedFileName = getResourcePath(iconPath);

    if (resolvedFileName != null) {
      return new ImageIcon(resolvedFileName, description);
    } else {
      logger.warning("Couldn't find file: " + iconFileName);
      return null;
    }
  }

  public static Object createInstance(String className)
  {
    Class c = null;

    try {
      c = Class.forName(className);
      return c.newInstance();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return null;
    } catch (InstantiationException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return null;
  }

  /**
   * Load properties using the class name as path
   * 
   * 
   * @param obj -
   *            Ussually sent in as this
   * @param extension -
   *            eg. ".properties" or ".props"
   * @return
   */
  // TODO - Need to rethink this if all properties files in single
  // flat directory (for simplicity)
  /*
  public static Properties loadProperties(Object obj, String extension)
  {
    String name = obj.getClass().getName();
    name = name.replaceAll("[.]", "/") + extension;
    System.out.println("Looking up props for " + name);
    return loadProperties(name);
  }
  */

  /**
   * 
   * This method reads and combines properties from all occurances of
   * propFileName found on the classpath.
   * 
   * @param propFileName -
   *            The name of the property file to read
   * @return The combined set of properties found in all files named
   *         propFileName.
   */
  public static Properties loadProperties(String propFileName)
  {
    Properties props = new Properties();

    // All properties stored under project/build/properties.  Eclipse has
    // 'build' in class path by default, so add the properties subdir
    // here so we don't need to add properties subdir to class path
    String propPath = "properties/" + propFileName;

    try {
      Enumeration e = ClassLoader.getSystemResources(propPath);

      // Should be at least one resource found...
      if( !e.hasMoreElements() ) {
        logger.warning("Can't find property file " + propPath);
        logger.warning("Please create one and place in your classpath");
      }
      else
      {
        while (e.hasMoreElements()) {
          URL url = (URL) e.nextElement();
          System.out.println("Loading properties from " + url);
          props.load(url.openStream());
        }
      }
    } catch (IOException e1) {
      logger.warning("Can't find property file " + propPath);
      logger.warning("Please create one and place in your classpath");
    }

    // Environment access only supported starting with J2SE 5.0
    if( envMap != null )
      replaceEnvVariables(props);

    // List out all properties if debugging level is enabled
    if( logger.isLoggable(Level.FINE) )
      props.list(System.out);

    return props;
  }

  /**
   * Support UNIX shell-like environment variables in property files.
   * This is useful for filename paths and other things, e.g.:
   *
   *  program.tmpFile=$HOME/tmp/tmpFile1
   *
   */
  private static void replaceEnvVariables(Properties props)
  {
    Enumeration e = props.propertyNames();

    while (e.hasMoreElements())
    {
      String propName = (String) e.nextElement();
      String propVal = props.getProperty(propName);

      // If at least 1, start replacing env vars...
      if (propVal.indexOf("${") >= 0)
      {
        System.out.println("propVal = " + propVal);
        int start = propVal.indexOf("${");
        int stop  = propVal.indexOf("}", start);
        String target = propVal.substring(start+2, stop);
        System.out.println("target = " + target);
        propVal = propVal.replaceAll("\\$\\{" +target +"\\}", (String) envMap.get(target));
        props.setProperty(propName, propVal);
        System.out.println("Transformed propVal = " + propVal);
      }

      if (propVal.indexOf("${") >= 0 ) {
        System.out.println("MrUtil.replaceEnvVariables: couldn'y find env var " + propVal);
      }
    }
  }

  /**
   *  Simple routine to dump a stack trace.  There may be a standard java
   *  way of doing this without using an exception, but I can't find it
   *  at the moment...
   */
  public static void printStackTrace()
  {
    IOException e = new IOException("StackTrace");
    e.printStackTrace();
  }
  

}
